package my.suveng.oauth2.service.user.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.caller.CallerUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.alibaba.fastjson.JSON;
import com.querydsl.core.QueryResults;
import com.querydsl.jpa.impl.JPAQueryFactory;
import my.suveng.model.common.interfaces.response.IMessage;
import my.suveng.model.common.response.Message;
import my.suveng.model.common.response.element.ElementPage;
import my.suveng.model.common.response.element.PageQuery;
import my.suveng.oauth2.model.dto.RoleAddPermissionDto;
import my.suveng.oauth2.model.dto.RoleDeleteDto;
import my.suveng.oauth2.model.dto.RoleEditDto;
import my.suveng.oauth2.model.dto.RoleSearch;
import my.suveng.oauth2.service.auth.impl.AuthServiceImpl;
import my.suveng.oauth2.service.db.mysql.dao.jpa.SysGroupRoleRepository;
import my.suveng.oauth2.service.db.mysql.dao.jpa.SysPermissionRoleRepository;
import my.suveng.oauth2.service.db.mysql.dao.jpa.SysRoleRepository;
import my.suveng.oauth2.service.db.mysql.model.entity.*;
import my.suveng.oauth2.service.transaction.UserTransactionService;
import my.suveng.oauth2.service.user.IRoleService;
import my.suveng.util.log.PlusLogFactoryHutool;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 *
 * @author suwenguang
 **/
@Service
public class RoleServiceImpl implements IRoleService {

    // hutool日志
    private static final Log log = LogFactory.setCurrentLogFactory(new PlusLogFactoryHutool())
            .getLog(CallerUtil.getCaller().getName());

    @Autowired
    private SysRoleRepository sysRoleRepository;
    @Autowired
    private JPAQueryFactory jpaQueryFactory;
    @Autowired
    private AuthServiceImpl authService;
    @Autowired
    private SysGroupRoleRepository sysGroupRoleRepository;
    @Autowired
    private SysPermissionRoleRepository sysPermissionRoleRepository;
    @Autowired
    private UserTransactionService userTransactionService;

    /**
     * 获取角色列表
     *
     * @author suwenguang
     */
    public IMessage<ElementPage<List<SysRole>>> roleList(PageQuery<RoleSearch> query) {
        Specification<SysRole> specification = buildSpecification(query);
        Sort.Order order = query.order();

        Page<SysRole> list;
        Specification<SysRole> where = Specification.where(specification);

        if (ObjectUtil.isEmpty(order)) {
            list = sysRoleRepository.findAll(where, PageRequest.of(query.getCurrentPage() - 1, query.getPageSize()));
        } else {
            Sort sort = Sort.by(order);
            list = sysRoleRepository.findAll(where,
                    PageRequest.of(query.getCurrentPage() - 1, query.getPageSize(), sort));
        }

        return ElementPage.build(list.getTotalElements(), list.getContent());
    }

    private Specification<SysRole> buildSpecification(PageQuery<RoleSearch> query) {
        if (ObjectUtil.isEmpty(query) || ObjectUtil.isEmpty(query.getSearch())) {
            return null;
        }
        RoleSearch search = query.getSearch();

        return new Specification<SysRole>() {
            @Override
            public Predicate toPredicate(Root<SysRole> root, CriteriaQuery<?> query, CriteriaBuilder criteriaBuilder) {
                List<Predicate> list = new ArrayList<>();

                if (ObjectUtil.isNotEmpty(search.getId())) {
                    list.add(criteriaBuilder.equal(root.get("id").as(Long.class), search.getId()));
                }

                // name模糊查询
                if (StrUtil.isNotBlank(search.getName())) {
                    list.add(criteriaBuilder.like(root.get("name").as(String.class), "%" + search.getName() + "%"));
                }

                if (ObjectUtil.isNotEmpty(search.getCreator())) {
                    list.add(criteriaBuilder.equal(root.get("creator").as(Long.class), search.getCreator()));
                }

                if (ObjectUtil.isNotEmpty(search.getUpdator())) {
                    list.add(criteriaBuilder.equal(root.get("updator").as(Long.class), search.getUpdator()));
                }

                if (ObjectUtil.isNotEmpty(search.getStatus())) {
                    list.add(criteriaBuilder.equal(root.get("status").as(Integer.class), search.getStatus()));
                }

                // 时间
                if (StrUtil.isNotBlank(search.getCreateTimeStart())) {
                    list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("createTime").as(String.class),
                            search.getCreateTimeStart()));

                }
                if (StrUtil.isNotBlank(search.getCreateTimeEnd())) {
                    list.add(criteriaBuilder.lessThan(root.get("createTime").as(String.class),
                            search.getCreateTimeEnd()));
                }

                // 时间
                if (StrUtil.isNotBlank(search.getModifyTimeStart())) {
                    list.add(criteriaBuilder.greaterThanOrEqualTo(root.get("modifyTime").as(String.class),
                            search.getModifyTimeStart()));
                }
                if (StrUtil.isNotBlank(search.getModifyTimeEnd())) {
                    list.add(criteriaBuilder.lessThan(root.get("modifyTime").as(String.class),
                            search.getModifyTimeEnd()));
                }

                Predicate[] p = new Predicate[list.size()];

                return criteriaBuilder.and(list.toArray(p));
            }
        };
    }

    /**
     * 修改角色信息
     *
     * @author suwenguang
     */
    public IMessage<SysRole> edit(RoleEditDto roleEditDto) {
        QSysRole qSysRole = QSysRole.sysRole;

        // 限制
        SysRole oldName = jpaQueryFactory.selectFrom(qSysRole).where(qSysRole.name.eq(roleEditDto.getName()))
                .fetchOne();
        if (ObjectUtil.isNotEmpty(oldName)) {
            log.info("修改的名称已存在,record={}", JSON.toJSONString(oldName));
            return Message.error("修改的名称已存在");
        }

        // 查询记录
        SysRole oldRole = jpaQueryFactory.selectFrom(qSysRole).where(qSysRole.id.eq(roleEditDto.getId())).fetchOne();
        if (ObjectUtil.isEmpty(oldRole)) {
            log.info("MySQL记录不存在,id={}", roleEditDto.getId());
            return Message.error("MySQL记录不存在");
        }

        // 修改记录
        oldRole.setName(roleEditDto.getName());
        oldRole.setModifyTime(new Date());

        SysUser user = authService.getSysUser();
        if (ObjectUtil.isEmpty(user)) {
            log.info("用户不存在");
            return Message.error("用户不存在");
        }

        oldRole.setUpdator(user.getId());
        SysRole newRole = sysRoleRepository.save(oldRole);
        return Message.successWithData(newRole);
    }

    /**
     * 删除角色信息
     *
     * @author suwenguang
     */
    public IMessage<Object> delete(RoleDeleteDto roleDeleteDto) {
        // 物理删除
        // 删除role-group关系
        QSysGroupRole qSysGroupRole = QSysGroupRole.sysGroupRole;
        QueryResults<SysGroupRole> sysGroupRoleQueryResults = jpaQueryFactory.selectFrom(qSysGroupRole)
                .where(qSysGroupRole.roleId.eq(roleDeleteDto.getId())).fetchResults();
        List<SysGroupRole> sysGroupRoleList = sysGroupRoleQueryResults.getResults();
        if (CollUtil.isNotEmpty(sysGroupRoleList)) {
            sysGroupRoleList.forEach(e -> {
                sysGroupRoleRepository.deleteById(e.getId());
            });
        }

        // 删除role记录
        sysRoleRepository.deleteById(roleDeleteDto.getId());
        return Message.success();
    }

    /**
     * 批量角色授予权限
     *
     * @author suwenguang
     */
    @Transactional(rollbackFor = Exception.class, propagation = Propagation.REQUIRES_NEW)
    public IMessage<List<SysPermissionRole>> addPermissions(RoleAddPermissionDto roleAddPermissionDto) {
        ArrayList<SysPermissionRole> result = new ArrayList<>();
        List<Long> permissionIds = roleAddPermissionDto.getPermissionIds();
        if (CollUtil.isNotEmpty(permissionIds)) {
            for (Long permissionId : permissionIds) {
                IMessage<SysPermissionRole> sysPermissionRoleMessage = roleAddPermission(roleAddPermissionDto.getId(),
                        permissionId);
                if (!sysPermissionRoleMessage.isSuccess()) {
                    throw new RuntimeException("事务异常");
                }
                result.add(sysPermissionRoleMessage.getData());
            }
        }

        return Message.successWithData(result);
    }

    /**
     * 角色授予权限
     *
     * @author suwenguang
     */
    public IMessage<SysPermissionRole> roleAddPermission(Long roleId, Long permissionId) {
        // 查询角色信息
        QSysRole qSysRole = QSysRole.sysRole;
        SysRole sysRole = jpaQueryFactory.selectFrom(qSysRole).where(qSysRole.id.eq(roleId)).fetchOne();
        if (ObjectUtil.isEmpty(sysRole)) {
            log.info("角色信息不存在,roleId={}", roleId);
            return Message.error("角色信息不存在");
        }

        // 查询权限信息
        QSysPermission qSysPermission = QSysPermission.sysPermission;
        SysPermission sysPermission = jpaQueryFactory.selectFrom(qSysPermission)
                .where(qSysPermission.id.eq(permissionId)).fetchOne();
        if (ObjectUtil.isEmpty(sysPermission)) {
            log.info("权限信息不存在,permissionId={}", permissionId);
            return Message.error("权限信息不存在");
        }

        // 增加角色-权限关系
        SysPermissionRole entity = new SysPermissionRole();
        entity.setPermissionId(roleId);
        entity.setRoleId(permissionId);

        SysUser sysUser = authService.getSysUser();
        if (ObjectUtil.isEmpty(sysUser)) {
            log.info("用户信息不存在,检查token");
            return Message.error("用户信息不存在,检查token");
        }
        entity.setCreator(sysUser.getId());
        entity.setUpdator(sysUser.getId());
        entity.setCreateTime(new Date());
        entity.setModifyTime(new Date());

        SysPermissionRole save = sysPermissionRoleRepository.save(entity);
        if (ObjectUtil.isEmpty(save.getId())) {
            log.info("role-permission关系入库失败,record={}", JSON.toJSONString(entity));
            return Message.error("role-permission关系入库失败");
        }

        return Message.successWithData(save);
    }

}
